package com.koushikdutta.ion.bitmap;

import com.example.ohosasynclibrary.async.util.LogUtil;
import com.example.ohosasynclibrary.async.util.StreamUtility;
import com.koushikdutta.ion.Ion;
import com.koushikdutta.ion.IonLog;
import ohos.agp.utils.Point;
import ohos.agp.utils.Rect;
import ohos.agp.window.service.Display;
import ohos.agp.window.service.DisplayManager;
import ohos.app.Context;
import ohos.app.IAbilityManager;
import ohos.global.resource.NotExistException;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import ohos.media.image.common.PixelFormat;
import ohos.media.image.common.Size;

import java.io.*;

/**
 * Created by koush on 5/23/13.
 */
public class IonBitmapCache {
    public static final long DEFAULT_ERROR_CACHE_DURATION = 30000L;
    private static final String TAG = IonBitmapCache.class.getName();

    //    Resource resources;
    Display metrics;


    LruBitmapCache cache;
    Ion ion;
    long errorCacheDuration = DEFAULT_ERROR_CACHE_DURATION;

    public long getErrorCacheDuration() {
        return errorCacheDuration;
    }

    public void setErrorCacheDuration(long errorCacheDuration) {
        this.errorCacheDuration = errorCacheDuration;
    }

    public IonBitmapCache(Ion ion) {
        Context context = ion.getContext();
        this.ion = ion;
        metrics = DisplayManager.getInstance().getDefaultDisplay(context).get();
//        final AssetManager mgr = context.getAssets();
//        resources = new Resources(mgr, metrics, context.getResources().getConfiguration());
//        RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(getPathById(context,));
        cache = new LruBitmapCache(getHeapSize() / 7);
    }

    public BitmapInfo remove(String key) {
        return cache.removeBitmapInfo(key);
    }

    public void clear() {
        cache.evictAllBitmapInfo();
    }

    double heapRatio = 1d / 7d;

    public double getHeapRatio() {
        return heapRatio;
    }

    public void setHeapRatio(double heapRatio) {
        this.heapRatio = heapRatio;
    }

    public void put(BitmapInfo info) {
        int maxSize = (int) (getHeapSize() * heapRatio);
        if (maxSize != cache.maxSize())
            cache.setMaxSize(maxSize);
        cache.put(info.key, info);
    }

    public void putSoft(BitmapInfo info) {
        cache.putSoft(info.key, info);
    }

    public BitmapInfo get(String key) {
        if (key == null)
            return null;

        // see if this thing has an immediate cache hit
        BitmapInfo ret = cache.getBitmapInfo(key);
        if (ret == null)
            return null;
        if (ret.bitmap != null && ret.bitmap.isReleased()) {
            IonLog.w("ION", "Cached bitmap was recycled.");
            IonLog.w("ION", "This may happen if passing Ion bitmaps directly to notification builders or remote media clients.");
            IonLog.w("ION", "Create a deep copy before doing this.");
            cache.remove(key);
            return null;
        }
        if (ret.exception == null)
            return ret;

        // if this bitmap load previously errored out, see if it is time to retry
        // the fetch. connectivity error, server failure, etc, shouldn't be
        // cached indefinitely...
        if (ret.loadTime + errorCacheDuration > System.currentTimeMillis())
            return ret;

        cache.remove(key);
        return null;
    }

    public void dump() {
        IonLog.i("IonBitmapCache", "bitmap cache: " + cache.size());
        IonLog.i("IonBitmapCache", "freeMemory: " + Runtime.getRuntime().freeMemory());
    }

    private Point computeTarget(int minx, int miny) {
        Point point = new Point();
        metrics.getRealSize(point);
        int targetWidth = minx;
        int targetHeight = miny;
        if (targetWidth == 0)
            targetWidth = point.getPointXToInt();
        if (targetWidth <= 0)
            targetWidth = Integer.MAX_VALUE;
        if (targetHeight == 0)
            targetHeight = point.getPointYToInt();
        if (targetHeight <= 0)
            targetHeight = Integer.MAX_VALUE;
        return new Point(targetWidth, targetHeight);
    }

    public ImageSource.DecodingOptions prepareBitmapOptions(Size size, int minx, int miny) throws BitmapDecodeException {
        if (size.width < 0 || size.height < 0)
            throw new BitmapDecodeException(size.width, size.height);
        Point target = computeTarget(minx, miny);
        int scale = Math.round(Math.max((float) size.width / target.getPointX(), size.height / target.getPointY()));
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.sampleSize = scale;
        decodingOptions.desiredSize = size;
//        decodingOptions.desiredRegion = new ohos.media.image.common.Rect(minx, miny, size.width, size.height);
//        decodingOptions.desiredPixelFormat = PixelFormat.ARGB_8888;
        return decodingOptions;
    }

//    public ImageSource.DecodingOptions prepareBitmapOptions(File file, int minx, int miny) throws BitmapDecodeException {
//        BitmapFactory.Options o = new BitmapFactory.Options();
//        o.inJustDecodeBounds = true;
//        BitmapFactory.decodeFile(file.toString(), o);
//        return prepareBitmapOptions(o, minx, miny);
//    }
//
//    public BitmapFactory.Options prepareBitmapOptions(byte[] bytes, int offset, int length, int minx, int miny) throws BitmapDecodeException {
//        BitmapFactory.Options o = new BitmapFactory.Options();
//        o.inJustDecodeBounds = true;
//        BitmapFactory.decodeByteArray(bytes, offset, length, o);
//        return prepareBitmapOptions(o, minx, miny);
//    }
//
//    public BitmapFactory.Options prepareBitmapOptions(Resources res, int id, int minx, int miny) throws BitmapDecodeException {
//        BitmapFactory.Options o = new BitmapFactory.Options();
//        o.inJustDecodeBounds = true;
//        BitmapFactory.decodeResource(res, id, o);
//        return prepareBitmapOptions(o, minx, miny);
//    }
//
//    public BitmapFactory.Options prepareBitmapOptions(InputStream in, int minx, int miny) throws BitmapDecodeException {
//        BitmapFactory.Options o = new BitmapFactory.Options();
//        o.inJustDecodeBounds = true;
//        BitmapFactory.decodeStream(in, null, o);
//        return prepareBitmapOptions(o, minx, miny);
//    }

//    private static PixelMap getRotatedBitmap(PixelMap bitmap, int rotation) {
//        if (bitmap == null)
//            return null;
//        if (rotation == 0)
//            return bitmap;
//
//        Matrix matrix = new Matrix();
//        matrix.postRotate(rotation);
//        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
//    }

    public static String getPathById(Context context, int id) {
        String path = "";
        if (context == null) {
            LogUtil.error(TAG, "getPathById -> get null context");
            return path;
        }
        ResourceManager manager = context.getResourceManager();
        if (manager == null) {
            LogUtil.error(TAG, "getPathById -> get null ResourceManager");
            return path;
        }
        try {
            path = manager.getMediaPath(id);
        } catch (IOException e) {
            LogUtil.error(TAG, "getPathById -> IOException");
        } catch (NotExistException e) {
            LogUtil.error(TAG, "getPathById -> NotExistException");
        } catch (WrongTypeException e) {
            LogUtil.error(TAG, "getPathById -> WrongTypeException");
        }
        return path;
    }

    public static ImageSource.SourceOptions prepareBitmapSourceOptions() {
        ImageSource.SourceOptions srcOpts = new ImageSource.SourceOptions();
        srcOpts.formatHint = "image/jpg";
        return srcOpts;
    }

    public static PixelMap loadBitmap(byte[] bytes, int offset, int length, ImageSource.DecodingOptions decodingOpts) {
        LogUtil.info("loadBitmap_bytes_0071","PixelMap");
        ImageSource imageSource = ImageSource.create(bytes, offset, length, prepareBitmapSourceOptions());
        int rotation = Exif.getOrientation(bytes, offset, length);
        decodingOpts.rotateDegrees = rotation * 1.0f;
//        decodingOpts.desiredSize = imageSource.getImageInfo().size;
//        decodingOpts.desiredRegion = new ohos.media.image.common.Rect(0, 0, imageSource.getImageInfo().size.width, imageSource.getImageInfo().size.height);
//        decodingOpts.desiredPixelFormat = imageSource.getImageInfo().pixelFormat;
        return imageSource.createPixelmap(decodingOpts);
    }

    //    @TargetApi(Build.VERSION_CODES.GINGERBREAD_MR1)
    public static PixelMap loadRegion(final ImageSource imageSource, Rect sourceRect, int inSampleSize) {
        LogUtil.info("loadRegion_ImageSource_0072","PixelMap");
//        BitmapFactory.Options options = new BitmapFactory.Options();
//        options.inSampleSize = inSampleSize;
        ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
        decodingOptions.sampleSize = inSampleSize;
//        decodingOptions.desiredRegion = new ohos.media.image.common.Rect(sourceRect.left, sourceRect.top, sourceRect.getWidth(), sourceRect.getHeight());
//        decodingOptions.desiredPixelFormat = imageSource.getImageInfo().pixelFormat;
        return imageSource.createPixelmap(decodingOptions);
    }


//    public static Bitmap loadBitmap(Resources res, int id, BitmapFactory.Options o) {
//        int rotation;
//        InputStream in = null;
//        RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(path);
//        try {
//            in = res.openRawResource(id);
//            byte[] bytes = new byte[50000];
//            int length = in.read(bytes);
//            rotation = Exif.getOrientation(bytes, 0, length);
//        } catch (Exception e) {
//            rotation = 0;
//        }
//        StreamUtility.closeQuietly(in);
//
//        Bitmap bitmap = BitmapFactory.decodeResource(res, id, o);
//
//        return getRotatedBitmap(bitmap, rotation);
//    }

    public static PixelMap loadBitmap(InputStream stream, ImageSource.DecodingOptions decodingOpts) throws IOException {
        LogUtil.info("loadBitmap_InputStream_0073","PixelMap");
//        int rotation;
//        MarkableInputStream in = new MarkableInputStream(stream);
//        in.mark(50000);
//        try {
//            byte[] bytes = new byte[50000];
//            int length = in.read(bytes);
//            rotation = Exif.getOrientation(bytes, 0, length);
//        } catch (Exception e) {
//            rotation = 0;
//        }
//        in.reset();
        ImageSource imageSource = ImageSource.create(stream, prepareBitmapSourceOptions());
//        decodingOpts.rotateDegrees = rotation * 1.0f;
//        decodingOpts.desiredSize = imageSource.getImageInfo().size;
//        decodingOpts.desiredRegion = new ohos.media.image.common.Rect(0, 0, imageSource.getImageInfo().size.width, imageSource.getImageInfo().size.height);
//        decodingOpts.desiredPixelFormat = imageSource.getImageInfo().pixelFormat;
        return imageSource.createPixelmap(decodingOpts);
    }

    public static PixelMap loadBitmap(File file, ImageSource.DecodingOptions decodingOpts) {
        LogUtil.info("loadBitmap_file_0074","PixelMap");
//        int rotation;
//        FileInputStream fin = null;
//        try {
//            fin = new FileInputStream(file);
//            byte[] bytes = new byte[50000];
//            int length = fin.read(bytes);
//            rotation = Exif.getOrientation(bytes, 0, length);
//        } catch (Exception e) {
//            rotation = 0;
//        }

//        StreamUtility.closeQuietly(fin);
//        try {
//            fin.reset();
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        try {
//            fin = new FileInputStream(file);
//        } catch (FileNotFoundException e) {
//            e.printStackTrace();
//        }

        ImageSource imageSource = ImageSource.create(file, prepareBitmapSourceOptions());
//        decodingOpts.rotateDegrees = rotation * 1.0f;
//        decodingOpts.desiredSize = imageSource.getImageInfo().size;
//        decodingOpts.desiredRegion = new ohos.media.image.common.Rect(0, 0, imageSource.getImageInfo().size.width, imageSource.getImageInfo().size.height);
//        decodingOpts.desiredPixelFormat = imageSource.getImageInfo().pixelFormat;
//        StreamUtility.closeQuietly(fin);
        return imageSource.createPixelmap(decodingOpts);
    }

    private static int getHeapSize() {
        return IAbilityManager.DEFAULT_HEAPSIZE * 1024 * 1024;
    }
}
